package system

import (
	"encoding/json"
	"fmt"
	"log"
	"project-info/src/handle/common"
	"project-info/src/handle/response"
	"project-info/src/lib"
	"project-info/src/model"
	"strconv"
	"strings"
	"time"

	"github.com/golang-jwt/jwt"
	"gorm.io/gorm"
)

type User struct {
	Username string `json:"username"`
	Password string `json:"password"`
}

type LoginRes struct {
	Token        string `json:"token"`
	RefreshToken string `json:"refresh_token"`
}

type UserInfo struct {
	UserName    string   `json:"userName"`
	Photo       string   `json:"photo"`
	Time        int64    `json:"time"`
	Roles       []string `json:"roles"`
	AuthBtnList []string `json:"authBtnList"`
}

type UserRoleList struct {
	RoleList []uint64 `json:"roleList"`
}

type AddUserReq struct {
	model.User
	UserRoleList
}

type PageUserReq struct {
	Username string `json:"userName"`
	common.PageRequest
}

type PageUserRecord struct {
	Id       uint64          `json:"id"`
	Username string          `json:"userName"`
	Describe string          `json:"describe"`
	Deleted  int8            `json:"deleted"`
	Meta     json.RawMessage `json:"meta" gorm:"type:json;column:meta"`
	RoleSign string          `json:"roleSign"`
	UserRoleList
}

type GetEmployeeListReq struct {
	SearchName string `json:"searchName"`
	common.PageRequest
}

type GetEmployeeListRes struct {
	List []EmployeesRes `json:"list"`
}

func Login(c *lib.GinContext) error {
	var user *User
	if err := c.Bind(&user); err != nil {
		log.Println("bind error:", err)
		return response.JsonFail(c, "绑定参数失败")
	}

	var u model.User
	model.DB().Where("username = ? and password = ? and deleted=0", user.Username, lib.Md5(user.Password)).First(&u)
	if u.Id == 0 {
		//return response.JsonResponse(c, http.StatusUnauthorized, nil, "用户名或密码错误", "")
		return response.JsonFail(c, "用户名或密码错误")
	}

	//生成jwttoken
	token, err := lib.JwtAuth(lib.Token{
		UserName: user.Username,
		UserId:   u.Id,
	}, &lib.TokenOptions{
		ExpireTime: model.JWT_EXPIRE,
		Secret:     model.JWT_SECRET,
	})
	if err != nil {
		log.Println("generate token error:", err)
		return response.JsonFail(c, "生成token失败")
	}
	return response.JsonOk(c, &LoginRes{
		Token: token,
	}, "ok")
}

func LoginOut(c *lib.GinContext) error {
	//TODO 退出登录
	return response.JsonOk(c, nil, "ok")
}

func GetUserInfo(c *lib.GinContext) error {
	// 获取token
	tokenValue, _ := c.Get(lib.JwtContextKey)
	token := tokenValue.(*jwt.Token)

	//1. 获取用户信息
	//2. 获取用户角色
	//3. 获取用户按钮权限
	userInfo := UserInfo{
		UserName:    token.Claims.(jwt.MapClaims)["name"].(string),
		Photo:       "https://wpimg.wallstcn.com/f778738c-e4f8-4870-b634-56703b4acafe.gif",
		Time:        time.Now().Unix(),
		Roles:       []string{"admin"},
		AuthBtnList: []string{"btn.add", "btn.del", "btn.edit", "btn.link"},
	}
	return response.JsonOk(c, userInfo, "ok")
}

// PageUser 分页查询用户
func PageUser(c *lib.GinContext) error {
	var pageUserReq *PageUserReq
	if err := c.Bind(&pageUserReq); err != nil {
		c.Logger().Error(err.Error())
		return response.JsonFail(c, "参数解析错误")
	}

	start, end := lib.Paging(pageUserReq.Page, pageUserReq.Size)

	var users []model.User
	var total int64

	db := model.DB().Model(&model.User{})
	if pageUserReq.Username != "" {
		db.Where("username like ?", fmt.Sprintf("%%%s%%", pageUserReq.Username))
	}
	db.Where("deleted = 0").Count(&total).Order("id desc").Offset(start).Limit(end).Find(&users)

	userRolesMap := getUserRolesMap()
	rolesMap := getRolesMap()

	var records []PageUserRecord
	for _, user := range users {
		records = append(records, PageUserRecord{
			Id:       user.Id,
			Username: user.Username,
			Describe: user.Describe,
			Deleted:  user.Deleted,
			Meta:     user.Meta,
			RoleSign: roleSignString(getObjRoles(rolesMap, userRolesMap[uint64(user.Id)])),
			UserRoleList: UserRoleList{
				RoleList: userRolesMap[uint64(user.Id)],
			},
		})
	}
	return response.JsonOk(c, map[string]interface{}{"records": records, "total": total}, "")
}

// AddUser 新增用户
func AddUser(c *lib.GinContext) error {
	var req *AddUserReq
	if err := c.Bind(&req); err != nil {
		c.Logger().Error(err.Error())
		return response.JsonFail(c, "参数解析错误")
	}

	var dbUser model.User
	model.DB().Where("username = ?", req.Username).Find(&dbUser)
	if dbUser.Username == req.Username && dbUser.Id != req.Id {
		return response.JsonFail(c, "用户名已存在")
	}

	var meta Meta
	err := json.Unmarshal([]byte(req.Meta), &meta)
	if err != nil {
		c.Logger().Error(err.Error())
		return response.JsonFail(c, err.Error())
	}

	model.DB().Transaction(func(tx *gorm.DB) error {
		user := &model.User{
			Id:       req.Id,
			Username: req.Username,
			Describe: req.Describe,
			Meta:     req.Meta,
			Deleted:  req.Deleted,
		}
		if req.Password == "" {
			user.Password = dbUser.Password
		} else {
			user.Password = lib.Md5(req.Password)
		}
		if user.Id == 0 {
			tx.Create(&user)
		} else {
			tx.Save(&user)
		}

		err := tx.Where("user_id = ?", user.Id).Delete(&model.RoleUser{}).Error
		if err != nil {
			return err
		}

		roleUsers := make([]model.RoleUser, 0)
		for _, roleId := range meta.RoleList {
			roleUsers = append(roleUsers, model.RoleUser{
				RoleId: roleId,
				UserId: uint64(user.Id),
			})
		}
		if len(roleUsers) > 0 {
			return tx.Create(&roleUsers).Error
		}
		return nil
	})

	return response.JsonOk(c, req, "ok")
}

// DeleteUser 删除用户
func DeleteUser(c *lib.GinContext) error {
	userIdP := c.QueryParam("id")
	userId, err := strconv.ParseUint(userIdP, 10, 64)
	if err != nil {
		c.Logger().Error(err.Error())
		return response.JsonFail(c, err.Error())
	}

	err = model.DB().Transaction(func(tx *gorm.DB) error {
		err = tx.Where("id = ?", userId).Delete(&model.User{}).Error
		if err != nil {
			return err
		}
		err = tx.Where("user_id = ?", userId).Delete(&model.RoleUser{}).Error
		if err != nil {
			return err
		}
		return nil
	})

	if err != nil {
		c.Logger().Error(err.Error())
		return response.JsonFail(c, err.Error())
	}
	return response.JsonOk(c, nil, "success")

}

// GetUserRoleIds 获取用户角色
func GetUserRoleIds(c *lib.GinContext) error {
	userIdP := c.QueryParam("id")
	userId, err := strconv.ParseUint(userIdP, 10, 64)
	if err != nil {
		c.Logger().Error(err.Error())
		return response.JsonFail(c, err.Error())
	}

	var roleUsers []model.RoleUser
	model.DB().Where("user_id = ?", userId).Find(&roleUsers)
	var roleIds []uint64
	for _, roleUser := range roleUsers {
		roleIds = append(roleIds, roleUser.RoleId)
	}
	return response.JsonOk(c, roleIds, "ok")
}

// GetUserOptions 获取用户选项
func GetUserOptions(c *lib.GinContext) error {
	var users []model.User
	err := model.DB().Model(&model.User{}).Select("id,username").Find(&users).Error
	if err != nil {
		c.Logger().Error(err.Error())
		return response.JsonFail(c, "查询失败")
	}
	var options []common.OptionRes
	for _, user := range users {
		options = append(options, common.OptionRes{Label: user.Username, Value: user.Id})
	}
	return response.JsonOk(c, options, "查询成功")
}

// getObjRoles 根据角色id获取角色对象
func getObjRoles(rolesMap map[uint64]model.Role, roleIds []uint64) []model.Role {
	m := make([]model.Role, 0)
	for _, id := range roleIds {
		m = append(m, rolesMap[id])
	}
	return m
}

// roleSignString 获取角色标识字符串
func roleSignString(roles []model.Role) string {
	var roleSigns []string
	for _, role := range roles {
		roleSigns = append(roleSigns, role.RoleName)
	}
	return strings.Join(roleSigns, ", ")
}

// getUserRolesMap 获取用户角色map
func getUserRolesMap() map[uint64][]uint64 {
	var roleUsers []model.RoleUser
	model.DB().Find(&roleUsers)
	userRoleMap := make(map[uint64][]uint64)
	for _, roleUser := range roleUsers {
		userRoleMap[roleUser.UserId] = append(userRoleMap[roleUser.UserId], roleUser.RoleId)
	}
	return userRoleMap
}

// getRolesMap 获取角色map
func getRolesMap() map[uint64]model.Role {
	var roles []model.Role
	model.DB().Find(&roles)
	roleMap := make(map[uint64]model.Role)
	for _, role := range roles {
		roleMap[role.Id] = role
	}
	return roleMap
}

// GetEmployeeList 获取员工列表
func GetEmployeeList(c *lib.GinContext) error {
	req := &GetEmployeeListReq{}
	err := c.Bind(req)
	if err != nil {
		c.Logger().Error(err.Error())
		return response.JsonFail(c, "参数绑定失败")
	}

	var employees []model.User
	db := model.DB().Model(&model.User{}).Select("id,username")
	if req.SearchName != "" {
		db = db.Where("username like ?", "%"+req.SearchName+"%")
	}
	err = db.Find(&employees).Error
	if err != nil {
		c.Logger().Error(err.Error())
		return response.JsonFail(c, "查询失败")
	}

	var employeeList []EmployeesRes
	for _, employee := range employees {
		employeeList = append(employeeList, EmployeesRes{
			Id:           employee.Id,
			EmployeeName: employee.Username,
		})
	}

	res := &GetEmployeeListRes{
		List: employeeList,
	}
	return response.JsonOk(c, res, "查询成功")
}
